﻿$import( "SmitearWebGL.Objects.Mesh" );

SmitearWebGL.Objects.Terrain.TerrainSection = SmitearWebGL.Objects.Mesh.extend(
{
	/* * * * * * * * constructor * * * * * * * */

	init : function( name,
					pParentSystem,
					sectorX,
					sectorY,
					heightMapX,
					heightMapY,
					xVerts,
					yVerts,
					sectorSize,
					worldExtents )
	{

		/* * * * * * * * public property * * * * * * * */

		/* * * * * * * * private property * * * * * * * */

		this._super( name );
		this._registClass( "SmitearWebGL.Objects.Terrain.TerrainSection" );

		this._pTerrainSystem = pParentSystem;

		this._sectorX = sectorX;
		this._sectorY = sectorY;

		this._heightMapX = heightMapX;
		this._heightMapY = heightMapY;

		this._xVerts = xVerts;
		this._yVerts = yVerts;

		this._invSectorCountX = 1.0 / pParentSystem.getSectorCountX();
		this._invSectorCountY = 1.0 / pParentSystem.getSectorCountY();

		var midX = sectorSize.x / 2.0;
		var midY = sectorSize.y / 2.0;

		this._sectorRect = new SmitearWebGL.Core.Geometry.Rect();
		this._sectorRect.x0 = - midX;
		this._sectorRect.x1 = midX;
		this._sectorRect.y0 = 0.0;
		this._sectorRect.y1 = 0.0;
		this._sectorRect.z0 = - midY;
		this._sectorRect.z1 = midY;

		this._position.x =  worldExtents.x0 + ( sectorX * sectorSize.x ) + midX;
		this._position.y =  0.0;
		this._position.z =  worldExtents.z0 + ( sectorY * sectorSize.y ) + midY;
		this._geometry.boudingBox = new SmitearWebGL.Core.Geometry.BoundingBox();
		this._geometry.boudingBox._localaabb.copy( this._sectorRect );

		this._buildVertexBuffer();
	}
	,

	/* * * * * * * * public method * * * * * * * */

	release : function()
	{
		this._super();
	}
	,
	renderCallBack : function( renderEntry, activationFlags )
	{
		var program = g_programManager.getResourceByHandle( renderEntry.hProgram );
		var material = g_materialManager.getResourceByHandle( renderEntry.hSurfaceMaterial );
		var systemBuffer = g_vertexBufferManager.getResourceByHandle( renderEntry.primaryParam );
		var vertexBuffer = g_vertexBufferManager.getResourceByHandle( renderEntry.modelParamA );
		var indexBuffer = g_indexBufferManager.getResourceByHandle( renderEntry.modelParamB );

		var hr = SmitearWebGL.Core.HResult.SUCCESS;
		var activationFlagBits = SmitearWebGL.Core.Render.RenderQueue.eActivationFlagBits;

		if ( activationFlags.testBit( activationFlagBits.k_activateRenderMethod ) )
		{
			hr |= program.activeShader();
		}

		hr |= program.activeUniform( this );

		if ( activationFlags.testBit( activationFlagBits.k_activateSurfaceMaterial ) )
		{
			hr |= this._setCullMode( material );
		}

		if ( activationFlags.testBit( activationFlagBits.k_activateModel ) )
		{
			hr |= systemBuffer.bind();
			hr |= systemBuffer.active( program.getShader() );
		}

		if ( activationFlags.testBit( activationFlagBits.k_activateModelParamA ) )
		{
			hr |= vertexBuffer.bind();
			hr |= vertexBuffer.active( program.getShader() );
		}

		if ( activationFlags.testBit( activationFlagBits.k_activateModelParamB ) )
		{
			hr |= indexBuffer.bind();
		}

		hr |= indexBuffer.draw( material.renderMode );

		return hr;
	}
	,
	buildRenderEntry : function( renderStage, renderQueue )
	{
		if ( renderStage == undefined ) return SmitearWebGL.Core.HResult.STAGE_UNKNOWN;

		var program = this._pTerrainSystem._getProgram( renderStage );
		if ( ! program ) return SmitearWebGL.Core.HResult.UNKNOWN_TECHNIQUE;
		if ( ! program.getShader() ) return SmitearWebGL.Core.HResult.UNKNOWN_SHADER;

		var pRenderEntry = renderQueue.lockRenderEntry();

		pRenderEntry.hProgram = program.getResourceHandle();
		pRenderEntry.hSurfaceMaterial = this._pTerrainSystem._material.getResourceHandle();
		pRenderEntry.primaryParam = this._pTerrainSystem._vertexBuffer.getResourceHandle();
		pRenderEntry.modelParamA = this._vertexBuffer.getResourceHandle();
		pRenderEntry.modelParamB = this._pTerrainSystem._indexBuffer.getResourceHandle();
		pRenderEntry.renderObject = this;
		pRenderEntry.userData = null;

		renderQueue.unlockRenderEntry( pRenderEntry );
	}
	,

	/* * * * * * * * private method * * * * * * * */

	_buildVertexBuffer : function()
	{
		this._geometry.boudingBox._localaabb.y0 = SmitearWebGL.Core.Math.MAX_NUMBER_VALUE;
		this._geometry.boudingBox._localaabb.y1 = SmitearWebGL.Core.Math.MIN_NUMBER_VALUE;

		var i = 0, y = 0, x = 0;

		this._vertexBuffer = g_vertexBufferManager.createResource( "__terrain_section_" + this.name + "_vb__" );
		this._vertexBuffer.createElementDescription( 1, 4 * 4, 0, SmitearWebGL.Resources.Buffer.DataType.FLOAT, SmitearWebGL.Resources.Buffer.AttribLocation.POSITION1 );
		this._vertexBuffer.createElementDescription( 3, 4 * 4, 1 * 4, SmitearWebGL.Resources.Buffer.DataType.FLOAT, SmitearWebGL.Resources.Buffer.AttribLocation.NORMAL );

		var pVerts = this._vertexBuffer.lock( this._xVerts * this._yVerts * 4 );

		for ( y = 0; y < this._yVerts; ++ y )
		{
			for ( x = 0; x < this._xVerts; ++ x )
			{
				var height = this._pTerrainSystem.readWorldHeightXY( this._heightMapX + x, this._heightMapY + y );
				var normal = this._pTerrainSystem.readWorldNormalXY( this._heightMapX + x, this._heightMapY + y );

				pVerts[i ++ ] = height;
				pVerts[i ++ ] = normal[0];
				pVerts[i ++ ] = normal[1];
				pVerts[i ++ ] = normal[2];

				this._geometry.boudingBox._localaabb.y0 = Math.min( this._geometry.boudingBox._localaabb.y0, height );
				this._geometry.boudingBox._localaabb.y1 = Math.max( this._geometry.boudingBox._localaabb.y1, height );
			}
		}

		this._vertexBuffer.unlock();
	}
}
);